<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <script src="https://cdn.bootcdn.net/ajax/libs/marked/2.0.3/marked.js"></script>
    <!-- <link rel="stylesheet" href="prism-dark.min.css"> -->
    <script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-2.1.1.min.js"></script>
        
    <script src="https://cdn.jsdelivr.net/npm/prismjs@1.17.1/prism.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/prismjs@1.17.1/components/prism-clike.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/prismjs@1.17.1/components/prism-c.min.js"></script>

    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>

    <title>网页AI页面</title>
    <style>
        body {
            font-family: sans-serif;
            font-size: 14px;
            background-color: #f2f2f2;
        }
        pre {
            overflow-y: auto;
        }
        #chat-box {
            max-width: 75%;
            margin: 0 auto;
            background-color: #fff;
            padding: 10px;
            border-radius: 5px;
            box-shadow: 0 0 5px #ccc;
            position: absolute;
            top: 10px;
            bottom: 10px;
            left: 20px;
            right: 20px;
        }
        #chat-box h2 {
            margin: 0;
            padding: 0;
            font-size: 16px;
            font-weight: bold;
            text-align: center;
            padding: 10px 0;
            border-bottom: 1px solid #ccc;
        }
        #chat-box .chat-messages {
            padding: 10px;
            height: calc(100% - 160px);
            overflow-y: auto;
            width: auto;
        }
        #chat-box .chat-messages .message {
            padding: 5px 10px;
            margin-bottom: 10px;
            border-radius: 5px;
            background-color: #f2f2f2;
            word-wrap: break-word;
        }
        #chat-box .chat-messages .message.self {
            white-space: pre-line;
            background-color: #ccc;
            text-align: right;
            word-wrap: break-word;
        }
        #chat-box .chat-form {
            padding: 10px;
            border-top: 1px solid #ccc;
            display: flex;
            align-items: center;
        }
        #chat-box .chat-form textarea[type="text"] {
            background-color: transparent;
            width: 100%;
            padding: 10px;
            box-sizing: border-box;
            border: 1px solid #ccc;
            height: 80px;
            margin-right: 10px;
            border-radius: 10px;
        }
        button {
            min-width: 80px;
            height: 80px;
            border-radius: 10px;
            border: 1px solid #ccc;
        }
        input {
            width: calc(100% - 175px);
            height:30px;
            border-radius:5px;
            background-color:transparent;
            border:1px solid #ccc;
        }
        .skkey{
            width:50px;
            height:30px;
        }
        .message textarea{
            border: none;
            background-color: transparent;
            width: 100%;
            height: 100%;
            resize: none;
        }

        #form {
            flex: 0 0 auto;
            height: 95px;
        }
        pre {
            border-radius: 5px;
            padding: 8px;
            background-color: rgb(41,45,62);
            color: #eee;
        }
        .copy {
            height: 20px;
            width: 40px;
        }
        button:hover {
            cursor: pointer;
        }
        table {
            border-collapse: collapse;
            width: 100%;
            border: 1px solid #aaa;
        }
        th, td {
            text-align: left;
            padding: 8px;
            border: 1px solid #aaa;
        }
        tr:nth-child(even){background-color: #f2f2f2}
        tr:nth-child(odd){background-color: #fafafa}
        ul {
            padding: 0px;
            list-style-type: none;
            border: 1px solid #aaa;
        }
        li {
            padding: 4px;
        }
        ul li:nth-child(even) {
            background-color: #ccc;
        }
        ul li:nth-child(odd) {
            background-color: #ddd;
        }
        @media screen and (max-width: 480px) {
            /* 样式 */
            #chat-box {
                max-width: 100%;
                left: 10px;
                right: 10px;
            }
            button {
                width: 84px;
                height: 84px;
            }
            #chat-box .chat-form textarea[type="text"] {
                width: 70%;
                margin-right: 3%;
            }
            input{
                width:100%;
            }
        }
        .fil {
            width: 18px;
            height: 2px;
            fill:#999
        }
        .men {
            background-color: #fff;
            width: 40px;
            height: 25px;
            border-radius: 6px;
            position: relative;
            box-shadow: 0 0 5px #ccc;
        }
        .men.open{
            animation-name: men-open;
            animation-duration: 0.5s;
            animation-fill-mode: forwards;
        }
        .men.off{
            animation-name: men-off;
            animation-duration: 0.5s;
            animation-fill-mode: forwards;
        }
        @keyframes men-open {
            0% {
                width: 40px;
                height: 25px;
            }
            50% {
                height: 100px;
            }
            100% {
                width: 200px;
                height: auto;
            }
        }
        @keyframes men-off {
            0% {
                width: 200px;
                height: auto;
            }
            50% {
                height: 100px;
            }
            100% {
                width: 40px;
                height: 25px;
            }
        }

        .men .title{
            padding: 5px;
            text-align: center;
            display: none;
            border-bottom: 1px solid;
            border-image: linear-gradient(90deg, rgba(255, 255, 255, 0) 0%, #ccc 50%, rgba(255, 255, 255, 0) 99%) 1 0;
        }
        .men ul{
            margin: 0px;
            border: none;
            display: none;
        }
        .men ul li{
            line-height: 1.5;
            padding: 8px;
            box-sizing: border-box;
            background-color: transparent;
            list-style-type: none;
        }
        .men ul li div{
            height: 100%;
            padding: 0;
            float:right;
        }
        .menubox{
            top: 20px;
            left: 20px;
            position: absolute;
        }
        #menubut{
            padding: 5px;
            width: 20px;
            height: 15px;
            left: 6px;
            position: absolute;
            transition: transform 0.3s;
        }
        #menubut.open{
            transform: rotate(180deg);
        }
        #menubut.off{
            transform: rotate(0deg);
        }
        #menubut.open .fil.top{
            transform: rotate(34deg);
        }
        #menubut.off .fil.top{
            transform: rotate(0deg);
            transition: transform 0.3s;
        }
        #menubut.open .fil.bottom{
            transform: rotate(-34deg);
        }
        #menubut.off .fil.bottom{
            transform: rotate(0deg);
            transition: transform 0.3s;
        }
        .coiled{
            width: 40px;
            height: 100%;
        }
        .purge{
            position: absolute;
            background-color: #fff;
            top: 20px;
            right: 15px;
            min-width: 40px;
            min-width: 40px;
            height: 25px;
            border-radius: 6px;
            box-shadow: 0 0 5px #ccc;
            border: 0px;
        }
        label {
            font: 1rem 'Fira Sans', sans-serif;
        }

        input[type="radio"] {
            width: 15px;
            height: 15px;
        }

        /** 高亮样式 */
        code[class*=language-],pre[class*=language-]{color:#eee;background:0 0;font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;text-shadow:0 -.1em .2em #000;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}:not(pre)>code[class*=language-],pre[class*=language-]{background:rgb(41,45,62)}pre[class*=language-]{border-radius:.5em;margin:.5em 0;overflow:auto;padding:1em}pre[class*=language-]::-moz-selection{background:#27292a}pre[class*=language-]::selection{background:#27292a}code[class*=language-]::-moz-selection,code[class*=language-]::-moz-selection,pre[class*=language-]::-moz-selection,pre[class*=language-]::-moz-selection{text-shadow:none;background:hsla(0,0%,93%,.15)}code[class*=language-]::selection,code[class*=language-]::selection,pre[class*=language-]::selection,pre[class*=language-]::selection{text-shadow:none;background:hsla(0,0%,93%,.15)}:not(pre)>code[class*=language-]{border-radius:.3em;border:.13em solid #545454;padding:.15em .2em .05em;white-space:normal}.token.comment{color:#aaa;}.token.function{color:#e00;}.token.punctuation{opacity:.7;color:#eee;}.namespace{opacity:.7}.token.boolean,.token.constant,.token.number,.token.property,.token.symbol,.token.tag{color:rgb(247,140,107)}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#bce051}.language-css .token.string,.style .token.string,.token.entity,.token.url,.token.variable{color:#eee;background:rgba(0,0,0,0);}.token.atrule,.token.attr-value,.token.keyword{color:rgb(156,113,132)}.token.important,.token.regex{color:#e90}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}.token.deleted{color:red}.token.operator{color:rgb(102,153,0);}
    </style>
</head>
<body onload="duqu()">
    <div id="chat-box">
        <div class="menubox">
            <div class="men">
                <svg id="menubut" onclick="openmenu()">
                    <rect class="fil top"/>
                    <rect class="fil middle" y="6"/>
                    <rect class="fil bottom" y="12"/>
                </svg>
                <div class="title choices">菜单</div>
                <ul class="choices">
                    <li class="choices">开启连续对话<div><button class="coiled choices">关闭中</button></div></li>
                    <li> <fieldset class="choices">
                        <legend class="choices">选择模型:</legend>
                        <div class="choices">
                          <input type="radio" name="drone" value="gpt3" class="choices">
                          <label for="dewey" class="choices">gpt3</label>
                        </input>
                        </div>
                    
                        <div class="choices">
                          <input type="radio" name="drone" value="gpt3.5" checked class="choices">
                          <label for="louie" class="choices">gpt3.5</label>
                          </input>
                        </div>
                    </fieldset></li>
                </ul>
            </div>
        </div>
        <h2>网页聊天界面</h2>
        <button class="purge">清除</button>
        <div class="chat-messages">
            <div class="message" style="width: auto;">
                <p>开启连续对话时，可能不显示代码高亮<br>按下shift+回车发送消息<br>双击代码区域复制代码</p>
            </div>
            <div class="message tips" style="width: auto;">
                <p>没有OpenAI的API密钥？</p>
                <a href="https://cn.bing.com/search?q=openai%E6%B3%A8%E5%86%8C&form=ANNTH1&refig=7ba400d256d64c13ba0873e8b461b562">查找申请攻略</a>
            </div>
            <div class="message" style="width: auto;">
                <p class="tips">在此填入OpenAI的API密钥开始。</p>
                <input type="text" id="key" placeholder="请输入sk，提交之后会存储到浏览器缓存中"/>
                <button class="skkey" onclick="tijiao()" id="tijiao">提交</button>
                <button class="skkey" onclick="shanchu()" id="shanchu">删除密钥</button>
                <button class="skkey" onclick="showkey()" id="showkey">显示密钥</button>
            </div>
        </div>
        <div id="form">
            <div class="chat-form">
                <textarea rows="4" cols="80" type="text" id="input"></textarea>
                <button onclick="fason()">发送[Shift+Enter]</button>
            </div>
        </div>
    </div>
</body>

<script defer>
    // let html = document.querySelector(".message p").innerHTML;
    // document.querySelector(".message p").innerHTML = marked(html);

    $(document).ready(function(){
        let e = localStorage.getItem('msg');//读取缓存消息
        if (e) {
            $(".coiled").text("已开启");
        } else {
            $(".coiled").text("关闭中");
        }

        // 初始化菜单
        $('.choices').children().hide();
    });

    function openmenu() {
        let className = $('#menubut').attr('class');
        if (className == 'open') {
            $('.choices').children().each(function(i){
                $(this).delay(100*i).hide();
            });
            $('.title').hide();
            $('.men ul').animate({opacity: 0}, 50);
            $('.men').removeClass('open')
            $('#menubut').attr('class', 'off');
            $('.fil.bottom').animate({x: 0,y: 12,width: 18,height: 2}, 30);
            $('.fil.top').animate({x: 0,y: 0,width: 18,height: 2}, 30);
        } else {
            $('.choices').children().each(function(i){
                $(this).delay(100*i).fadeIn(200);
            });
            $('.title').show();
            $('.men').addClass('open')
            $('#menubut').attr('class', 'open');
            $('.fil.bottom').animate({x: -5,y: 15,width: 16,height: 2}, 30);
            $('.fil.top').animate({x: 3,y: -5,width: 16,height: 2}, 30);
            setTimeout($('.men ul').show(), 300);
            $('.men ul').animate({opacity: 100}, 50);
        }
    }

    document.getElementById("input").addEventListener("keydown", function(event) {
        if (event.shiftKey && event.keyCode == 13) {
            fason();
            setTimeout(function(){
                document.getElementById("input").value = "";
            }, 100);
        }
    });
    $("#input").focus(function(){ 
        let className = $('#menubut').attr('class');
        if (className == 'open') openmenu();
    }); 
    $(".chat-messages").click(function(){ 
        let className = $('#menubut').attr('class');
        if (className == 'open') openmenu();
    }); 

    $(".coiled").click(function() {
        if ($(this).text() == "关闭中") {
            $(this).text("已开启");
        } else {
            $(this).text("关闭中");
        }
    });
    $(".purge").click(function() {
        $(".purge").text(`清除`);
        $(".chat-messages").children().remove();
        $(".chat-messages").append('<div class="message" style="width: auto;"><p>开启连续对话时，可能不显示代码高亮<br>按下shift+回车发送消息<br>双击代码区域复制代码</p></div>');
        localStorage.setItem('msg', '');
    });

    function showkey() {
        let sk = localStorage.getItem('sk-key');
        if ($("#key").attr("disabled")) {
            $("#key").attr("disabled",false);
            $("#key").val(sk);
            $("#showkey").text("隐藏密钥");
        } else {
            $("#key").attr("disabled",true);
            $("#key").val('');
            $("#showkey").text("显示密钥");
        }
    }

    function shanchu() {
        localStorage.removeItem("sk-key");
        $("#tijiao").show();
        $(".tips").show();
        $("#showkey").hide();
        $("#key").attr("disabled",false);
        $("#key").attr("placeholder","请输入sk，提交之后会存储到浏览器缓存中")
    }

    function duqu() {
        let sk = localStorage.getItem('sk-key');
        if (sk) {
            $("#key").attr("placeholder","已提交：sk-*****")
            $("#key").attr("disabled",true);
            $("#tijiao").hide();
            $(".tips").hide();
            $("#showkey").show();
        } else {
            $("#showkey").hide();
        }
    }

    function tijiao() {
        //如果填入密匙有错误
        let reg = /sk-[a-zA-Z0-9]{16,}/;
        let sk = document.getElementById('key').value;
        if (!reg.test(sk)) {
            let chatMessages = document.querySelector('.chat-messages');
            chatMessages.innerHTML += `<div class="message self"><p style="color:red; font-weight:bold;">密匙格式填写错误！</p></div>`;
        } else {
            localStorage.setItem('sk-key', sk);
            $("#key").attr("placeholder","已提交：sk-*****")
            $("#key").attr("disabled",true);
            $("#key").val('');
            $("#tijiao").hide();
            $(".tips").hide();
            $("#showkey").show();
            let chatMessages = document.querySelector('.chat-messages');
            chatMessages.innerHTML += `<div class="message self"><p style="color:green; font-weight:bold;">提交成功！密匙已存储至浏览器缓存</p></div>`;
        }
    }

    // 开启连续对话 gpt3
    function lianxu(emsg) {
        //处理消息部分
        let e = localStorage.getItem('msg');//读取缓存消息
        if(e){
            var data_msg = `${e}\nHuman:${emsg}\nAI:`;
        }else{
            var data_msg = `Human:${emsg}\nAI:`;
        }
        console.log(data_msg)

        let sk = localStorage.getItem('sk-key');
        $.ajax({
            url: "https://api.openai.com/v1/completions",
            type: "POST",
            headers: {
                "Content-Type": "application/json",
                "Authorization": `Bearer ${sk}`
            },
            data: JSON.stringify({
                "model": "text-davinci-003",
                "prompt": 'Human:有代码时请用markdown表达式回复\nAI:JavaScript```\nconsole.log(\'好的\')\n```\n'+data_msg,
                "max_tokens": 1024,
                "temperature": 0,
                "stop": [" Human:", " AI:"],
                "presence_penalty": 0.6,
                "frequency_penalty": 0.0,
                "top_p": 1,
                "temperature": 0.9,
            }),
            success: function(data) {
                let msg = emsg.replace(/\n/g,'<br>');
                //结果返回错误
                if (data.error) {
                    $('.chat-messages').append(`<div class="message"><p>${response.error.message}</p></div>`);
                    $('#chat-box .chat-messages').scrollTop($('#chat-box .chat-messages')[0].scrollHeight);
                    return true;
                }
                let res = data.choices[0].text;
                $(".purge").text(`清除(${data.usage.prompt_tokens})`);
                localStorage.setItem('msg', data_msg+res);//提交对话内容到缓存

                if(!res.match(/```$/) && res.match(/``$/)) {
                    var chatmsg = marked(res+'`');
                    console.log('已添加一个`')
                } else {
                    var chatmsg = marked(res);
                }
                $('.chat-messages').append(`<div class="message">${chatmsg}</div>`);
                $('#chat-box .chat-messages').scrollTop($('#chat-box .chat-messages')[0].scrollHeight);
                // 为页面上所有的pre元素添加以下事件
                $('pre').on({
                    mouseenter: function(){
                        $(this).select();
                    },
                    click: function(){
                        var startTime = new Date().getTime();
                        $(this).mouseup(function(){
                            var endTime = new Date().getTime();
                            if(endTime - startTime < 500){
                                let copyText = $(this).text();
                                let textArea = document.createElement('textarea');
                                textArea.value = copyText;
                                document.body.appendChild(textArea);
                                textArea.select();
                                document.execCommand('copy');
                                document.body.removeChild(textArea);
                            }
                        });
                    }
                });
            }
        });
    }

    var gpt35_msg = []
    function gpt35(emsg) {
        gpt35_msg.push({"role": "user", "content": emsg})
        let sk = localStorage.getItem('sk-key');
        $.ajax({
            url: "https://openai.geekr.cool/v1/chat/completions",
            type: "POST",
            headers: {
                "Content-Type": "application/json",
                "Authorization": `Bearer ${sk}`
            },
            data: JSON.stringify({
                "model": "gpt-3.5-turbo",
                "messages": gpt35_msg
            }),
            success: function(data){
                let msg = emsg.replace(/\n/g,'<br>');
                //结果返回错误
                if (data.error) {
                    $('.chat-messages').append(`<div class="message"><p>${res.error.message}</p></div>`);
                    $('#chat-box .chat-messages').scrollTop($('#chat-box .chat-messages')[0].scrollHeight);
                    return true;
                }
                let res = data.choices[0].message.content;
                gpt35_msg.push({"role": "assistant", "content": res})
                $(".purge").text('已处理：' + data.usage.total_tokens);
                $('.purge').off('click').on('click', function() {
                    gpt35_msg = [];$(".purge").text('已处理数量')
                });
                let chatmsg = marked(res);
                
                $('.chat-messages').append(`<div class="message">${chatmsg}</div>`);
                $('#chat-box .chat-messages').scrollTop($('#chat-box .chat-messages')[0].scrollHeight);
                // 为页面上所有的pre元素添加以下事件
                $('pre').on({
                    mouseenter: function(){
                        $(this).select();
                    },
                    click: function(){
                        var startTime = new Date().getTime();
                        $(this).mouseup(function(){
                            var endTime = new Date().getTime();
                            if(endTime - startTime < 500){
                                let copyText = $(this).text();
                                let textArea = document.createElement('textarea');
                                textArea.value = copyText;
                                document.body.appendChild(textArea);
                                textArea.select();
                                document.execCommand('copy');
                                document.body.removeChild(textArea);
                            }
                        });
                    }
                });
            }
        })
    }

    // 不开启连续对话 gpt3 , 发送方法
    function fason() {
        let emsg = document.getElementById('input').value;
        //如果没有填入密钥
        let sk = localStorage.getItem('sk-key');
        if (!sk) {
            let chatMessages = document.querySelector('.chat-messages');
            chatMessages.innerHTML += `<div class="message self"><p style="color:red; font-weight:bold;">请先提交密钥！</p></div>`;
            return true;
        }
        $('.chat-messages').append($('<div>').addClass('message self').text(emsg));
        $("#input").val('');
        $('#chat-box .chat-messages').scrollTop($('#chat-box .chat-messages')[0].scrollHeight);

        // 判断模型
        if($('input:radio[name="drone"]:checked').val() == 'gpt3.5'){
            gpt35(emsg)
            return true;
        }

        // 已开启连续对话
        if($(".coiled").text() == '已开启'){
            lianxu(emsg);
            return true;
        }

        var xhr = new XMLHttpRequest();
        xhr.open("POST", "https://api.openai.com/v1/completions", true);
        xhr.setRequestHeader("Content-Type", "application/json");
        xhr.setRequestHeader("Authorization", `Bearer ${sk}`);
        xhr.send(JSON.stringify({
            "model": "text-davinci-003",
            "prompt": '请用markdown表达式回复。'+emsg,
            "max_tokens": 2048, 
            "temperature": 0,
        }));

        xhr.onreadystatechange = function() {
            if (xhr.readyState == 4 && xhr.status == 200) {
                let response = JSON.parse(xhr.responseText);
                //结果返回错误
                if (response.error) {
                    $('.chat-messages').append(`<div class="message"><p>${response.error.message}</p></div>`);
                    return true;
                }
                let res = response.choices[0].text;
                console.log(res);
                let chatmsg = marked(res);

                $('.chat-messages').append(`<div class="message">${chatmsg}</div>`);
                // $('.chat-messages').append($('<div>').text(chatmsg).html(),$('<div>').addClass('message'));
                // chatMessages.innerHTML += `<div class="message">${chatmsg}</div>`;
                $('#chat-box .chat-messages').scrollTop($('#chat-box .chat-messages')[0].scrollHeight);
                console.log(response.choices[0].text);
                document.querySelectorAll('code').forEach(function(block) {
                    Prism.highlightAll(block);
                });
                // 为页面上所有的pre元素添加以下事件
                $('pre').on({
                    mouseenter: function(){
                        $(this).select();
                    },
                    click: function(){
                        var startTime = new Date().getTime();
                        $(this).mouseup(function(){
                            var endTime = new Date().getTime();
                            if(endTime - startTime < 500){
                                let copyText = $(this).text();
                                let textArea = document.createElement('textarea');
                                textArea.value = copyText;
                                document.body.appendChild(textArea);
                                textArea.select();
                                document.execCommand('copy');
                                document.body.removeChild(textArea);
                            }
                        });
                    }
                });
            }
        }
    }

</script>
</html>